<template>
  <div class="v-table">
    <ElTable
      ref="ElTable"
      :key="tableKey"
      :data="tableData"
      v-bind="tableProps"
      v-on="tableListeners"
      class="v-table__content"
    >
      <template #empty>
        <template v-if="!baseConfig.emptyContentRender">
          <span v-if="!isError" class="ElTable__empty-text">暂无数据</span>
          <span v-else class="el-icon-refresh" style="color: red;cursor: pointer;" @click="refresh">点击刷新</span>
        </template>
        <custom-render
          v-else
          :refresh="refresh"
          :is-error="isError"
          :render="baseConfig.emptyContentRender"
        />
      </template>
  
      <ElTableColumn
        v-for="(column, index) in tableColumns"
        :key="column.options.prop + index"
        v-bind="column.options"
      >
        <template v-if="column.render" v-slot="scoped">
          <custom-render
            v-bind="scoped"
            :value="scoped.row | formatValue(column)"
            :render="column.render"
          />
        </template>
        <template v-else-if="!column.options.type" v-slot="{ row }">
          {{ row | formatValue(column) }}
        </template>
      </ElTableColumn>
    </ElTable>

    <div class="v-table__footer">
      <ColumnSetting
        v-if="baseConfig.useSetting"
        :columns.sync="baseConfig.columns"
        :name="baseConfig.name"
      />

      <ElPagination
        v-if="isShowPagination"
        :current-page="currentPage"
        :page-size="pageSize"
        :page-count="totalPages"
        :total="totalCount"
        layout="total, prev, pager, next, jumper"
        @current-change="getTableData"
      />
    </div>
  </div>
</template>

<script>
import ColumnSetting from './ColumnSetting.vue'
import CustomRender from '../../../CustomRender'

import { tableProps as defTableProps, queryKeyMap } from '@lib/default'
import { normalizeConfig } from './normalizeConfig'
import { parsePath } from '../../../utils'
import { clone, isArray, isFunction, isNumber } from 'lodash-es'
import { useTableSettingRecord } from './tableSettingRecord'

export default {
  components: {
    CustomRender,
    ColumnSetting,
  },

  filters: {
    formatValue(row, column) {
      const value = parsePath(row, column.options.prop)
      if (isFunction(column.transform)) {
        return column.transform(value)
      } else {
        return value
      }
    }
  },

  props: {
    config: { required: true, type: Object }
  },

  data() {
    return {
      baseConfig: {},
      // 表格数据
      tableData: [],
      // 当前页数
      currentPage: 1,
      // 总页数
      totalPages: undefined,
      // 总条数
      totalCount: undefined,
      // 页条数
      pageSize: 1,
      // 请求出现错误
      isError: false,
      // 用来重载table组件
      tableKey: Symbol(),
      // 请求接口时，传递的查询参数
      query: {},
      // 用于记录表格的滚动距离
      scrollOffset: { left: 0, top: 0 },
      // 是否已经初始化过
      initialized: false
    }
  },

  inject: ['eventsControler'],

  computed: {
    tableColumns() {
      return (this.baseConfig.columns || []).filter(item => {
        return item.show
      })
    },
    // 表格属性
    tableProps() {
      return Object.assign({}, defTableProps, this.baseConfig.options)
    },
    // 表格监听事件
    tableListeners() {
      const listeners = clone(this.baseConfig.listeners)
      listeners['header-dragend'] = this.onTableColumnWidthChange
      listeners['selection-change'] = this.onSelectionChange
      return listeners
    },
    // 是否显示分页
    isShowPagination() {
      return isNumber(this.totalCount) && isNumber(this.totalPages)
    }
  },

  created() {
    this.baseConfig = normalizeConfig(this.config)
    this.eventsControler.on('set-table-query-params', (query) => {
      Object.assign(this.query, query)
    })
  },

  mounted() {
    this.baseConfig.immediate && this.getTableData()
  },

  activated() {
    this.setScrollOffset()

    // keep-alive重新回来，如果带有fixed的操作栏，可能会出现错位
    if (this.baseConfig.columns.some(item => item.options.fixed)) {
      this.$nextTick(() => {
        this.$refs.ElTable.doLayout()
      })
    }
  },

  deactivated() {
    this.saveScrollOffset()
  },

  methods: {
    /**
     * 获取表格数据
     */
    async getTableData() {
      const fieldsMap = this.baseConfig.fieldsMap
      const loading = this.$loading({ target: this.$refs.ElTable.$el, lock: true })
      try {
        const params = {
          [queryKeyMap.page]: this.currentPage,
          [queryKeyMap.pageSize]: this.baseConfig.requestApi.pageSize
        }
        const res = await this.baseConfig.requestApi.handler({
          ...params,
          ...this.baseConfig.extraRequestParams,
          ...this.query
        })

        // 重载table组件
        if (this.isError || this.tableData.length === 0) {
          this.tableKey = Symbol()
          this.isError = false
        }

        const tableData = parsePath(res, fieldsMap.list)
        if (isArray(tableData)) {
          this.tableData = tableData
        } else {
          console.error('表格列表需要为一个数组，请配置fieldsMap.list，实际得到的数据为：', tableData)
        }

        this.totalPages = parsePath(res, fieldsMap.totalPages)
        this.totalCount = parsePath(res, fieldsMap.totalCount)
        this.pageSize = parsePath(res, fieldsMap.pageSize)

        this.baseConfig.requestApi.onSuccess(res)

        // 调用doLayout优化布局错误的问题
        if (!this.initialized) {
          this.$nextTick(() => {
            this.$refs.ElTable.doLayout()
          })
        }

        // 重置y轴滚动
        this.$nextTick(() => {
          this.$refs.ElTable.$el.querySelector('.el-table__body-wrapper').scrollTop = 0
        })

        this.initialized = true
        // this.fixHandleColumnBorder()
      } catch (e) {
        this.isError = true
        this.tableData = []
        this.baseConfig.requestApi.onError(e)
      } finally {
        this.baseConfig.requestApi.onComplete()
        loading.close()
      }
    },
    /**
     * 选择项发生变化
     */
    onSelectionChange(items) {
      this.eventsControler.emit('selection-change', items)
      const onChange = this.baseConfig.listeners['selection-change']
      if (onChange) {
        onChange(items)
      }
    },
    /**
     * 记录滚动距离
     */
    saveScrollOffset() {
      const tableBody = this.$refs.ElTable.$el.querySelector('.el-table__body-wrapper')
      if (tableBody) {
        const { scrollTop: top, scrollLeft: left } = tableBody
        this.scrollOffset = { top, left }
      }
    },
    /**
     * 重新设置滚动距离
     */
    setScrollOffset() {
      const tableBody = this.$refs.ElTable.$el.querySelector('.el-table__body-wrapper')
      if (tableBody) {
        setTimeout(() => {
          tableBody.scrollTop = this.scrollOffset.top
          tableBody.scrollLeft = this.scrollOffset.left
        })
      }
    },
    /**
     * 用户调整表格列宽度
     */
    onTableColumnWidthChange() {
      // 缓存表格列的宽度
      const key = this.baseConfig.name
      if (key) {
        const record = this.$refs.ElTable.columns.reduce((res, item) => {
          if (item.width) {
            res[item.property] = parseInt(item.width)
          }
          return res
        }, {})
        const { setRecord } = useTableSettingRecord(key)
        setRecord('width', record)
      }

      // 表格宽度调整可能造成固定位置的列布局错位
      const hasFixedColumn = this.baseConfig.columns.some(col => col.options.fixed)
      if (hasFixedColumn) {
        this.$nextTick(() => {
          this.$refs.ElTable.doLayout()
        })
      }

      const onChange = this.baseConfig.listeners['header-dragend']
      if (onChange) {
        onChange(...arguments)
      }
    },
    /**
     * 搜索
     */
    search(query) {
      this.query = query
      this.getTableData()
    },
    /**
     * 刷新
     */
    refresh() {
      this.getTableData()
    },
    /**
     * 刷新字典
     */
    refreshDicts(prop) {
      const item = this.baseConfig.columns.find(item => item.options.prop === prop)
      item && item.refreshDicts && item.refreshDicts()
    },
    /**
     * 修改fixed: 'right'的列，如果表格没有横向滚动条的情况下，这一列没有显示边框的bug
     * 目前的方案是调用doLayout方法，并把这一列的宽度减1
     */
    // fixHandleColumnBorder: once(function() {
    //   this.$nextTick(() => {
    //     const lastColumn = this.baseConfig.columns.slice(-1)[0]
    //     if (
    //       lastColumn &&
    //       lastColumn.options.fixed === 'right' &&
    //       this.$refs.ElTable.$el.getElementsByClassName('is-scrolling-none').length > 0
    //     ) {
    //       this.$refs.ElTable.doLayout()
    //       setTimeout(() => {
    //         const fixedRightEl = this.$refs.ElTable.$el.getElementsByClassName('el-table__fixed-right')[0]
    //         fixedRightEl.style.width = `${parseFloat(fixedRightEl.style.width) - 1}px`
    //       })
    //     }
    //   })
    // })
  }
}
</script>

<style lang="less">
.v-table {
  display: flex;
  flex-direction: column;

  &__content {
    flex: 1;
    overflow: auto;
    width: 100%;
  }

  &__footer {
    display: flex;
    margin-top: 10px;

    .el-pagination {
      margin-left: auto;
    }
  }
}
</style>
